  #include   <stdio.h>
  #include   <malloc.h>
  #include   <math.h>
  #include   <stdlib.h>
    
  #define   PI   3.1415927   
  #define   widthbytes(i)   ((i+31)/32*4)   
    
  int   sampleYH,sampleYV,sampleUH,sampleUV,sampleVH,sampleVV;   
  int   HYtoU,VYtoU,HYtoV,VYtoV,YinMCU,UinMCU,VinMCU;   
  int   compressnum=0,Qt[3][64],*YQt,*UQt,*VQt,codepos[4][16],codelen[4][16];   
  unsigned   char   compressindex[3],YDCindex,YACindex,UVDCindex,UVACindex;   
  unsigned   char   HufTabindex,And[9]={0,1,3,7,0xf,0x1f,0x3f,0x7f,0xff};   
  unsigned   int   codevalue[4][256],hufmax[4][16],hufmin[4][16];   
  int   bitpos=0,curbyte=0,run=0,value=0,MCUbuffer[10*64],blockbuffer[64];   
  int   ycoef=0,ucoef=0,vcoef=0,intervalflag=0,interval=0,restart=0;   
  long   Y[4*64],U[4*64],V[4*64],QtZMCUbuffer[10*64];   
  unsigned   long   imgwidth=0,imgheight=0,width=0,height=0,linebytes;   
  int   Z[8][8]={{0,1,5,6,14,15,27,28},{2,4,7,13,16,26,29,42},   
            {3,8,12,17,25,30,41,43},{9,11,18,24,31,40,44,53},   
                            {10,19,23,32,39,45,52,54},{20,22,33,38,46,51,55,60},   
                            {21,34,37,47,50,56,59,61},{35,36,48,49,57,58,62,63}};   
    
  struct{   
    unsigned   char   type[2];   
    long   size;   
    long   reserved;   
    long   offset;   
    }head;   
    
  struct{   
    long   size;   
    long   width;   
    long   height;   
    int   plane;   
    int   bitcount;   
    long   compression;   
    long   imagesize;   
    long   xpels;   
    long   ypels;   
    long   colorused;   
    long   colorimportant;   
    }bmp; 
    
  void   error(char   *s)   
    {   
      printf("%s\n",s);   
      exit(1);   
    }   
    
    
  void   makebmpheader(FILE   *fp)   
    {   
      int   i,j;   
      unsigned   long   colorbits,imagebytes;   
      colorbits=24;   
      linebytes=widthbytes(colorbits*imgwidth);   
      imagebytes=(unsigned   long)imgheight*linebytes;   
      head.type[0]='B';head.type[1]='M';   
      head.size=imagebytes+0x36;   
      head.reserved=0;   
      head.offset=0x36;   
      fwrite(&head,sizeof(head),1,fp);   
      bmp.size=0x28;   
      bmp.width=(long)imgwidth;   
      bmp.height=(long)imgheight;   
      bmp.plane=1L;   
      bmp.bitcount=colorbits;   
      bmp.compression=0;   
      bmp.imagesize=imagebytes;   
      bmp.xpels=0xece;   
      bmp.ypels=0xec4;   
      bmp.colorused=0;   
      bmp.colorimportant=0;   
      fwrite(&bmp,sizeof(bmp),1,fp);   
      for(j=0;j<imgheight;j++)   
        for(i=0;i<linebytes;i++)   
          fputc(0,fp);   
    }   
    
  void   initialize(FILE   *fp)   
    {   
      unsigned   char   *p,*q,hfindex,qtindex,number;   
      int   i,j,k,finish=0,huftab1,huftab2,huftabindex,count;   
      unsigned   int   length,flag;   
      fread(&flag,sizeof(unsigned   int),1,fp);   
      if(flag!=0xd8ff)   
        error("Error   Jpg   File   format!");   
      while(!finish)     {   
        fread(&flag,sizeof(unsigned   int),1,fp);   
        fread(&length,sizeof(int),1,fp);   
        length=((length<<8)|(length>>8))-2;   
        switch(flag)     {   
          case   0xe0ff:   
    fseek(fp,length,1);break;   
          case   0xdbff:   
    p=malloc(length);   
    fread(p,length,1,fp);   
    qtindex=(*p)&0x0f;   
    q=p+1;   
    if(length+2<80)   
      for(i=0;i<64;i++)   
        Qt[qtindex][i]=(int)*(q++);   
    else     {   
      for(i=0;i<64;i++)   
        Qt[qtindex][i]=(int)*(q++);   
      qtindex=*(q++)&0x0f;   
      for(i=0;i<64;i++)   
        Qt[qtindex][i]=(int)*(q++);   
    }   
                    free(p);break;   
          case   0xc0ff:   
    p=malloc(length);   
    fread(p,length,1,fp);   
    imgheight=((*(p+1))<<8)+(*(p+2));   
    imgwidth=((*(p+3))<<8)+(*(p+4));   
    compressnum=*(p+5);   
    if((compressnum!=1)&&(compressnum!=3))   
      error("Error   Jpg   File   format!");   
    if(compressnum==3)     {   
      compressindex[0]=*(p+6);   
      sampleYH=(*(p+7))>>4;   
      sampleYV=(*(p+7))&0x0f;   
      YQt=(int   *)Qt[*(p+8)];   
      compressindex[1]=*(p+9);   
      sampleUH=(*(p+10))>>4;   
      sampleUV=(*(p+10))&0x0f;   
      UQt=(int   *)Qt[*(p+11)];   
      compressindex[2]=*(p+12);   
      sampleVH=(*(p+13))>>4;   
      sampleVV=(*(p+13))&0x0f;   
      VQt=(int   *)Qt[*(p+14)];   
    }   
                    else     {   
      compressindex[0]=*(p+6);   
      sampleYH=(*(p+7))>>4;   
      sampleYV=(*(p+7))&0x0f;   
      YQt=(int   *)Qt[*(p+8)];   
                      compressindex[1]=*(p+6);   
                      sampleUH=1;   
                      sampleUV=1;   
      UQt=(int   *)Qt[*(p+8)];   
                      compressindex[2]=*(p+6);   
                      sampleVH=1;   
                      sampleVV=1;   
      VQt=(int   *)Qt[*(p+8)];   
    }   
                    free(p);break;   
          case   0xc4ff:   
    p=malloc(length+1);   
    fread(p,length,1,fp);   
    p[length]=0xff;   
    if(length+2<0xd0)     {   
      huftab1=(int)(*p)>>4;   
      huftab2=(int)(*p)&0x0f;   
      huftabindex=huftab1*2+huftab2;   
      q=p+1;   
      for(i=0;i<16;i++)   
        codelen[huftabindex][i]=(int)(*(q++));   
      j=0;   
      for(i=0;i<16;i++)   
        if(codelen[huftabindex][i]!=0)     {   
          k=0;   
          while(k<codelen[huftabindex][i])     {   
            codevalue[huftabindex][k+j]=(int)(*(q++));   
            k++;   
          }   
          j+=k;   
        }   
        i=0;   
        while(codelen[huftabindex][i]==0)   i++;   
        for(j=0;j<i;j++)     {   
          hufmin[huftabindex][j]=0;   
          hufmax[huftabindex][j]=0;   
        }   
        hufmin[huftabindex][i]=0;   
        hufmax[huftabindex][i]=codelen[huftabindex][i]-1;   
        for(j=i+1;j<16;j++)     {   
          hufmin[huftabindex][j]=(hufmax[huftabindex][j-1]+1)<<1;   
          hufmax[huftabindex][j]=hufmin[huftabindex][j]+codelen[huftabindex][j]-1;   
        }   
        codepos[huftabindex][0]=0;   
        for(j=1;j<16;j++)   
          codepos[huftabindex][j]=codelen[huftabindex][j-1]+codepos[huftabindex][j-1];   
    }   
    else     {   
      hfindex=*p;   
      while(hfindex!=0xff)     {   
        huftab1=(int)hfindex>>4;   
        huftab2=(int)hfindex&0x0f;   
        huftabindex=huftab1*2+huftab2;   
        q=p+1;   
        count=0;   
        for(i=0;i<16;i++)     {   
          codelen[huftabindex][i]=(int)(*(q++));   
          count+=codelen[huftabindex][i];   
        }   
        count+=17;   
        j=0;   
        for(i=0;i<16;i++)   
          if(codelen[huftabindex][i]!=0)   {   
            k=0;   
            while(k<codelen[huftabindex][i])     {   
              codevalue[huftabindex][k+j]=(int)(*(q++));   
              k++;   
            }   
            j+=k;   
          }   
          i=0;   
          while(codelen[huftabindex][i]==0)     i++;   
          for(j=0;j<i;j++)     {   
            hufmin[huftabindex][j]=0;   
            hufmax[huftabindex][j]=0;   
          }   
          hufmin[huftabindex][i]=0;   
          hufmax[huftabindex][i]=codelen[huftabindex][i]-1;   
          for(j=i+1;j<16;j++)     {   
            hufmin[huftabindex][j]=(hufmax[huftabindex][j-1]+1)<<1;   
            hufmax[huftabindex][j]=hufmin[huftabindex][j]+codelen[huftabindex][j]-1;   
          }   
          codepos[huftabindex][0]=0;   
          for(j=1;j<16;j++)   
            codepos[huftabindex][j]=codelen[huftabindex][j-1]+codepos[huftabindex][j-1];   
          p+=count;   
          hfindex=*p;   
      }   
      p-=length;   
    }   
    free(p);break;   
          case   0xddff:   
    p=malloc(length);   
    fread(p,length,1,fp);   
                    restart=((*p)<<8)|(*(p+1));   
                    free(p);break;   
          case   0xdaff:   
    p=malloc(length*sizeof(unsigned   char));   
    fread(p,length,1,fp);   
    number=*p;   
    if(number!=compressnum)   
      error("Error   Jpg   File   format!");   
    q=p+1;   
    for(i=0;i<compressnum;i++)     {   
      if(*q==compressindex[0])     {   
        YDCindex=(*(q+1))>>4;   
        YACindex=((*(q+1))&0x0f)+2;   
      }   
      else   {   
        UVDCindex=(*(q+1))>>4;   
        UVACindex=((*(q+1))&0x0f)+2;   
      }   
      q+=2;   
    }   
    finish=1;   
                    free(p);break;   
          case   0xd9ff:   
    error("Error   Jpg   File   format!");break;   
          default:   
                    if((flag&0xf000)!=0xd000)   
      fseek(fp,length,1);   
                    break;   
        }   
      }   
    }   
    
  void   savebmp(FILE   *fp)   
    {   
      int   i,j;   
      unsigned   char   r,g,b;   
      long   y,u,v,rr,gg,bb;   
      for(i=0;i<sampleYV*8;i++)     {   
        if((height+i)<imgheight)     {   
          fseek(fp,(unsigned   long)(imgheight-height-i-1)*linebytes+3*width+54,0);   
          for(j=0;j<sampleYH*8;j++)     {   
            if((width+j)<imgwidth)     {   
              y=Y[i*8*sampleYH+j];   
              u=U[(i/VYtoU)*8*sampleYH+j/HYtoU];   
              v=V[(i/VYtoV)*8*sampleYH+j/HYtoV];   
              /*rr=y+((359*v)>>8;
              gg=y-((88*u-183*v)>>8);
              bb=((y<<8)+301*u)>>8; */
              rr=(long)(y+1.402*v);
              gg=(long)(y-0.34414*u-0.71414*v);
              bb=(long)(y+1.772*u);
              r=(unsigned   char)rr;   
              g=(unsigned   char)gg;   
              b=(unsigned   char)bb;   
              if(rr&0xffffff00)   if   (rr>255)   r=255;   else   if   (rr<0)   r=0;   
              if(gg&0xffffff00)   if   (gg>255)   g=255;   else   if   (gg<0)   g=0;   
              if(bb&0xffffff00)   if   (bb>255)   b=255;   else   if   (bb<0)   b=0;   
              fputc(b,fp);fputc(g,fp);fputc(r,fp);   
            }   
          else     break;   
        }   
      }   
      else   break;   
      }   
    }   
    
  unsigned   char   readbyte(FILE   *fp)   
    {   
      unsigned   char   c;   
      c=fgetc(fp);   
      if(c==0xff)   
        fgetc(fp);   
      bitpos=8;   
      curbyte=c;   
      return   c;   
    }   
    
  int   DecodeElement(FILE   *fp)   
    {   
      int   codelength;   
      long   thiscode,tempcode;   
      unsigned   int   temp,new;   
      unsigned   char   hufbyte,runsize,tempsize,sign;   
      unsigned   char   newbyte,lastbyte;   
      if(bitpos>=1)   {   
        bitpos--;   
        thiscode=(unsigned   char)curbyte>>bitpos;   
        curbyte=curbyte&And[bitpos];   
      }   
      else     {   
        lastbyte=readbyte(fp);   
        bitpos--;   
        newbyte=curbyte&And[bitpos];   
        thiscode=lastbyte>>7;   
        curbyte=newbyte;   
      }   
      codelength=1;   
      while((thiscode<hufmin[HufTabindex][codelength-1])||   
  (codelen[HufTabindex][codelength-1]==0)||   
  (thiscode>hufmax[HufTabindex][codelength-1]))     {   
        if(bitpos>=1)     {   
          bitpos--;   
          tempcode=(unsigned   char)curbyte>>bitpos;   
          curbyte=curbyte&And[bitpos];   
        }   
        else     {   
          lastbyte=readbyte(fp);   
          bitpos--;   
          newbyte=curbyte&And[bitpos];   
          tempcode=(unsigned   char)lastbyte>>7;   
          curbyte=newbyte;   
        }   
        thiscode=(thiscode<<1)+tempcode;   
        codelength++;   
        if(codelength>16)   
          error("Error   Jpg   File   format!");   
      }   
      temp=thiscode-hufmin[HufTabindex][codelength-1]+codepos[HufTabindex][codelength-1];   
      hufbyte=(unsigned   char)codevalue[HufTabindex][temp];   
      run=(int)(hufbyte>>4);   
      runsize=hufbyte&0x0f;   
      if(runsize==0)     {   
        value=0;   
        return   1;   
      }   
      tempsize=runsize;   
      if(bitpos>=runsize)     {   
        bitpos-=runsize;   
        new=(unsigned   char)curbyte>>bitpos;   
        curbyte=curbyte&And[bitpos];   
      }   
      else     {   
        new=curbyte;   
        tempsize-=bitpos;   
        while(tempsize>8)     {   
          lastbyte=readbyte(fp);   
          new=(new<<8)+(unsigned   char)lastbyte;   
          tempsize-=8;   
        }   
        lastbyte=readbyte(fp);   
        bitpos-=tempsize;   
        new=(new<<tempsize)+(lastbyte>>bitpos);   
        curbyte=lastbyte&And[bitpos];   
      }   
      sign=new>>(runsize-1);   
      if(sign)   
        value=new;   
      else     {   
        new=new^0xffff;   
        temp=0xffff<<runsize;   
        value=-(int)(new^temp);   
      }   
      return   1;   
    }   
    
  int   HufBlock(FILE   *fp,unsigned   char   dchufindex,   
                            unsigned   char   achufindex)   
    {   
      int   i,count=0;   
      HufTabindex=dchufindex;   
      if(DecodeElement(fp)!=1)   
        return   0;   
      blockbuffer[count++]=value;   
      HufTabindex=achufindex;   
      while   (count<64)     {   
        if(DecodeElement(fp)!=1)   
          return   0;   
        if((run==0)&&(value==0))     {   
          for(i=count;i<64;i++)   
            blockbuffer[i]=0;   
          count=64;   
        }   
        else     {   
          for(i=0;i<run;i++)   
            blockbuffer[count++]=0;   
          blockbuffer[count++]=value;   
        }   
      }   
      return   1;   
    }   
    
  int   DecodeMCUBlock(FILE   *fp)   
    {   
      int   i,j,*pMCUBuffer;   
      if(intervalflag)     {   
        fseek(fp,2,1);   
        ycoef=ucoef=vcoef=0;   
        bitpos=0;   
        curbyte=0;   
      }   
      switch(compressnum)     {   
        case   3:   
                      pMCUBuffer=MCUbuffer;   
                      for(i=0;i<sampleYH*sampleYV;i++)     {   
                        if(HufBlock(fp,YDCindex,YACindex)!=1)   
                          return   0;   
                        blockbuffer[0]=blockbuffer[0]+ycoef;   
                        ycoef=blockbuffer[0];   
                        for(j=0;j<64;j++)   
                          *pMCUBuffer++=blockbuffer[j];   
                      }   
                      for(i=0;i<sampleUH*sampleUV;i++)     {   
                        if(HufBlock(fp,UVDCindex,UVACindex)!=1)   
                          return   0;   
                        blockbuffer[0]=blockbuffer[0]+ucoef;   
                        ucoef=blockbuffer[0];   
                        for(j=0;j<64;j++)   
                          *pMCUBuffer++=blockbuffer[j];   
                      }   
                      for(i=0;i<sampleVH*sampleVV;i++)     {   
        if(HufBlock(fp,UVDCindex,UVACindex)!=1)   
                          return   0;   
                        blockbuffer[0]=blockbuffer[0]+vcoef;   
                        vcoef=blockbuffer[0];   
                        for(j=0;j<64;j++)   
                          *pMCUBuffer++=blockbuffer[j];   
                      }   
                      break;   
        case   1:   
                      pMCUBuffer=MCUbuffer;   
      if(HufBlock(fp,YDCindex,YACindex)!=1)   
                        return   0;   
                      blockbuffer[0]=blockbuffer[0]+ycoef;   
                      ycoef=blockbuffer[0];   
                      for(j=0;j<64;j++)   
                        *pMCUBuffer++=blockbuffer[j];   
                      for(i=0;i<128;i++)   
                        *pMCUBuffer++=0;   
                      break;   
        default:   
                        error("Error   Jpg   File   format");   
      }   
      return(1);   
    }   
    
  void   idct(long   *p,int   k)   
    {   
      long   x,x0,x1,x2,x3,x4,x5,x6,x7;   
      x1=p[k*4]<<11;x2=p[k*6];x3=p[k*2];x4=p[k*1];   
      x5=p[k*7];x6=p[k*5];x7=p[k*3];x0=(p[0]<<11)+1024;   
      x=565*(x4+x5);x4=x+2276*x4;x5=x-3406*x5;   
      x=2408*(x6+x7);x6=x-799*x6;x7=x-4017*x7;   
      x=1108*(x3+x2);x2=x-3784*x2;x3=x+1568*x3;   
      x=x6;x6=x5+x7;x5-=x7;x7=x0+x1;x0-=x1;x1=x+x4;x4-=x;   
      x=x5;x5=x7-x3;x7+=x3;x3=x0+x2;x0-=x2;   
      x2=(181*(x4+x)+128)>>8;x4=(181*(x4-x)+128)>>8;   
      p[0]=(x7+x1)>>11;p[k*1]=(x3+x2)>>11;   
      p[k*2]=(x0+x4)>>11;p[k*3]=(x5+x6)>>11;   
      p[k*4]=(x5-x6)>>11;p[k*5]=(x0-x4)>>11;   
      p[k*6]=(x3-x2)>>11;p[k*7]=(x7-x1)>>11;   
    }   
    
  void   IDCTint(long   *metrix)   
    {   
      int   i;   
      for(i=0;i<8;i++)   
        idct(metrix+8*i,1);   
      for(i=0;i<8;i++)   
        idct(metrix+i,8);   
    }   
    
  void   IQtZBlock(int   *s,long   *d,int   *pQt,int   correct)   
    {   
      int   i,j,tag;   
      long   *pbuffer,buffer[8][8];   
      for(i=0;i<8;i++)   
        for(j=0;j<8;j++)   {   
          tag=Z[i][j];   
          buffer[i][j]=(long)s[tag]*(long)pQt[tag];   
        }   
      pbuffer=(long   *)buffer;   
      IDCTint(pbuffer);   
      for(i=0;i<8;i++)   
        for(j=0;j<8;j++)   
          d[i*8+j]=(buffer[i][j]>>3)+correct;   
    }   
    
  void   IQtZMCU(int   xx,int   yy,int   offset,int   *pQt,int   correct)   
    {   
      int   i,j,*pMCUBuffer;   
      long   *pQtZMCUBuffer;   
      pMCUBuffer=MCUbuffer+offset;   
      pQtZMCUBuffer=QtZMCUbuffer+offset;   
      for(i=0;i<yy;i++)   
        for(j=0;j<xx;j++)   
          IQtZBlock(pMCUBuffer+(i*xx+j)*64,pQtZMCUBuffer+(i*xx+j)*64,pQt,correct);   
    }   
    
  void   getYUV(int   xx,int   yy,long   *buf,int   offset)   
    {   
      int   i,j,k,n;   
      long   *pQtZMCU;   
      pQtZMCU=QtZMCUbuffer+offset;   
      for(i=0;i<yy;i++)   
        for(j=0;j<xx;j++)   
          for(k=0;k<8;k++)   
            for(n=0;n<8;n++)   
              buf[(i*8+k)*sampleYH*8+j*8+n]=*pQtZMCU++;   
    }   
    
  void   decode(FILE   *fp1,FILE   *fp2)   
    {   
      int   Yinbuf,Uinbuf,Vinbuf;   
      YinMCU=sampleYH*sampleYV;   
      UinMCU=sampleUH*sampleUV;   
      VinMCU=sampleVH*sampleVV;   
      HYtoU=sampleYH/sampleUH;   
      VYtoU=sampleYV/sampleUV;   
      HYtoV=sampleYH/sampleVH;   
      VYtoV=sampleYV/sampleVV;   
      Yinbuf=0;Uinbuf=YinMCU*64;   
      Vinbuf=(YinMCU+UinMCU)*64;   
      while(DecodeMCUBlock(fp1))     {   
        interval++;   
        if((restart)&&(interval%restart==0))   
          intervalflag=1;   
        else   
          intervalflag=0;   
        IQtZMCU(sampleYH,sampleYV,Yinbuf,YQt,128);   
        IQtZMCU(sampleUH,sampleUV,Uinbuf,UQt,0);   
        IQtZMCU(sampleVH,sampleVV,Vinbuf,VQt,0);   
        getYUV(sampleYH,sampleYV,Y,Yinbuf);   
        getYUV(sampleUH,sampleUV,U,Uinbuf);   
        getYUV(sampleVH,sampleVV,V,Vinbuf);   
        savebmp(fp2);   
        width+=sampleYH*8;   
        if(width>=imgwidth)   {   
          width=0;   
          height+=sampleYV*8;   
        }   
        if((width==0)&&(height>=imgheight))   
          break;   
      }   
    }   
    
  main(   )   
    {   
      FILE   *fp1,*fp2;   
      char srcjpeg[100],destbmp[100];
      printf("Please input source JPEG image name:");
      scanf("%s",srcjpeg);
      printf("Please input destination BMP image name:");
      scanf("%s",destbmp);
      if((fp1=fopen(srcjpeg,"rb"))==NULL)
        error("Can   not   open   Jpg   File!");   
      if((fp2=fopen(destbmp,"wb"))==NULL)
        error("Can   not   create   Bmp   File!");   
      initialize(fp1);   
      makebmpheader(fp2);decode(fp1,fp2);   
      fclose(fp1);fclose(fp2);
      printf("Press any key to exit!");
      getch();
    }   
